﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;

namespace SICOMSocket
{
    public class SocketAsyncServer
    {

        public delegate void ProcessMessageeDelegate(Socket clientSock, byte[] msgBuff, DateTime getDataTime);
        public event ProcessMessageeDelegate ProcessMessageeEnvent;

        public delegate void ClearFlag();
        public event ClearFlag Clear;

        public delegate void NewConnectDelegate(string IP, string port, Socket clinetSocket);
        public event NewConnectDelegate NewConnectEnvent;

        public delegate void ClientShutDownDelegate(string IP, string port);
        public event ClientShutDownDelegate ClientShutDownEnvent;


        private Socket serverSock;
        byte[] msgBuff = new byte[1024];

        public void Start(int port)
        {
            try
            {
                serverSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                serverSock.Bind(new IPEndPoint(IPAddress.Any, port));
                serverSock.Listen(10);
                Console.WriteLine("开始监听端口" + port + "......");
                serverSock.BeginAccept(new AsyncCallback(OnConnectRequest), serverSock);
            }
            catch (Exception ex)
            {
                Console.WriteLine("监听端口" + port + "失败，请检查该端口是否被占用！ " + ex.Message);
            }
        }

        public void OnConnectRequest(IAsyncResult ar)
        {
            try
            {
                Socket listenerSock = (Socket)ar.AsyncState;
                NewConnection(listenerSock.EndAccept(ar));
                listenerSock.BeginAccept(new AsyncCallback(OnConnectRequest), listenerSock);
                Console.WriteLine("已接受远程连接！");
            }
            catch (Exception ex)
            {
                Console.WriteLine("新链接创建错误：" + ex.Message);
            }
        }

        private void NewConnection(Socket clientSock)
        {
            try
            {
                EndPoint tempRemoteEP = clientSock.RemoteEndPoint;
                IPEndPoint tempRemoteIP = (IPEndPoint)tempRemoteEP;
                string rempip = tempRemoteIP.Address.ToString();
                string remoport = tempRemoteIP.Port.ToString();
                NewConnectEnvent(rempip, remoport, clientSock);
                Clear();
                AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
                clientSock.BeginReceive(msgBuff, 0, msgBuff.Length, SocketFlags.None, recieveData, clientSock);
            }
            catch (Exception ex)
            {
                Console.WriteLine("接收回调函数设置失败 {0}", ex.Message);
            }
        }

        public void OnRecievedData(IAsyncResult ar)
        {
            Socket sock = (Socket)ar.AsyncState;
            try
            {
                DateTime getDataTime = DateTime.Now;
                int nBytesRec = sock.EndReceive(ar);
                if (nBytesRec > 0)
                {
                    byte[] recievedNowBuff = new byte[nBytesRec];
                    Array.Copy(msgBuff, recievedNowBuff, nBytesRec);
                    try
                    {
                        AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
                        sock.BeginReceive(msgBuff, 0, msgBuff.Length, SocketFlags.None, recieveData, sock);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("接收回调函数设置失败 {0}", ex.Message);
                    }

                    System.Threading.Thread t1 = new System.Threading.Thread(delegate() { ProcessMessageeEnvent(sock, recievedNowBuff, getDataTime); });
                    t1.Start();
                }
                else
                {
                    Console.WriteLine("连接中断 {0}", sock.RemoteEndPoint);
                    EndPoint tempRemoteEP = sock.RemoteEndPoint;
                    IPEndPoint tempRemoteIP = (IPEndPoint)tempRemoteEP;
                    string rempip = tempRemoteIP.Address.ToString();
                    string remoport = tempRemoteIP.Port.ToString();
                    sock.Shutdown(SocketShutdown.Both);
                    sock.Close();
                    ClientShutDownEnvent(rempip, remoport);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message, "未知错误!");
            }
        }
    }

}
